/****   LED Control Functions   ***************************************************************************
These functions are called, and in some cases combined to create LED sequences
***********************************************************************************************************/

// ***RGB functions set all three color channels for one or more LEDs***
// ***These always replace previous settings for the LED

// set one rgb LED
void set_led_rgb (uint8_t led,uint8_t red,uint8_t green,uint8_t blue) {
  if (led>11) 
    return;
  brightness[0][led]=red;
  brightness[1][led]=green;
  brightness[2][led]=blue;
}

// set cardinal quarters (3 rgb LEDs) the same
void set_front_rgb (uint8_t red,uint8_t green,uint8_t blue) {
    set_led_rgb(0,red,green,blue);
    set_led_rgb(1,red,green,blue);
    set_led_rgb(11,red,green,blue);
}
void set_left_rgb (uint8_t red,uint8_t green,uint8_t blue) {
  for (uint8_t led=2;led<5;led++)
    set_led_rgb(led,red,green,blue);
}
void set_rear_rgb (uint8_t red,uint8_t green,uint8_t blue) {
  for (uint8_t led=5;led<8;led++)
    set_led_rgb(led,red,green,blue);
}
void set_right_rgb (uint8_t red,uint8_t green,uint8_t blue) {
  for (uint8_t led=8;led<11;led++)
    set_led_rgb(led,red,green,blue);
}

// set odd numbered rgb LEDs the same
void set_odd_rgb (uint8_t red,uint8_t green,uint8_t blue) {
  for (uint8_t led=0;led<11;led=led+2)
    set_led_rgb(led,red,green,blue);
}

// set even numbered rgb LEDs the same
void set_even_rgb (uint8_t red,uint8_t green,uint8_t blue) {
  for (uint8_t led=1;led<12;led=led+2)
    set_led_rgb(led,red,green,blue);
}

// set all rgb LEDs the same
void set_all_rgb (uint8_t red,uint8_t green,uint8_t blue) {
  for (uint8_t led=0;led<12;led++)
    set_led_rgb(led,red,green,blue);
}

// ***Single channel functions set individual color for one or more LEDs***
// ***These only replace previous settings for specified color, and can be additive

// sets one color channel on one LED.  var is brightness.
void set_led_unicolor (uint8_t led,uint8_t rgb,uint8_t var) {
  if(rgb>2||led>11)  
    return;
  brightness[rgb][led]=var;
}

// sets one color channel on all LEDs.  varis brightnes
void set_all_unicolor (uint8_t rgb,uint8_t var) {
  for (uint8_t led=0;led<12;led++) {
    set_led_unicolor(led,rgb,var);
  }
}

// ***Static layouts. Useful for running lights in combination with flashers***

void LED_layout (uint8_t layout) {
  if (layout==0) { // *****  std navi light layout
    set_led_rgb (0,0,0,0);
    set_led_rgb (1,0,0,0);
    set_led_rgb (2,255,0,0);
    set_led_rgb (3,255,0,0);
    set_led_rgb (4,0,0,0);
    set_led_rgb (5,0,0,0);
    set_led_rgb (6,255,255,255);
    set_led_rgb (7,0,0,0);
    set_led_rgb (8,0,0,0);
    set_led_rgb (9,0,255,0);
    set_led_rgb (10,0,255,0);
    set_led_rgb (11,0,0,0);
  }
  if (layout==1) { // *****  MWC navi light layout
    set_front_rgb (0,0,255);
    set_led_rgb (2,255,255,255);
    set_led_rgb (3,255,255,255);
    set_led_rgb (4,0,0,0);
    set_rear_rgb (255,0,0);
    set_led_rgb (8,0,0,0);
    set_led_rgb (9,255,255,255);
    set_led_rgb (10,255,255,255);
  }
  if (layout==2) { // *****  RGB color wheel
    set_led_rgb(0,255,0,0);
    set_led_rgb(1,192,64,0);
    set_led_rgb(2,128,128,0);
    set_led_rgb(3,64,192,0);
    set_led_rgb(4,0,255,0);
    set_led_rgb(5,0,192,64);
    set_led_rgb(6,0,128,128);
    set_led_rgb(7,0,64,192);
    set_led_rgb(8,0,0,255);
    set_led_rgb(9,64,0,192);
    set_led_rgb(10,128,0,128);
    set_led_rgb(11,192,0,64);
  }
}

//***Moving sequence functions***

// rgb variable speed flasher (t1=off interval, t2=on interval)
// call for each LED
void ledFlasher (uint8_t led,uint8_t red,uint8_t green,uint8_t blue,int t1,int t2) {
  if (millis()<(ledlastflashtime+t2))
    set_led_rgb(led,red,green,blue);
  else 
    if (millis()<(ledlastflashtime+t1+t2))
      set_led_rgb(led,0,0,0);
    else
      ledlastflashtime=millis();
}

// rgb variable speed flasher (t1=off interval, t2=on interval)
// call once for entire ring
void ringFlasher (uint8_t red,uint8_t green,uint8_t blue,int t1,int t2) {
  if (millis()<(ledlastflashtime+t2))
    set_all_rgb(red,green,blue);
  else 
    if (millis()<(ledlastflashtime+t1+t2))
      set_all_rgb(0,0,0);
    else
      ledlastflashtime=millis();
}

// rgb double flasher (t1=off interval, t2=on interval)
// increase 125ms value to slow down strobing
// call for each LED
void dblFlasher (uint8_t led,uint8_t red,uint8_t green,uint8_t blue,int t1,int t2) {
  if (millis()<(ledlastflashtime+t1))
    set_led_rgb(led,red,green,blue);
  else 
    if (millis()<(ledlastflashtime+t1+125))
      set_led_rgb(led,0,0,0);
    else
      if (millis()<(ledlastflashtime+2*t1+125))
        set_led_rgb(led,red,green,blue);
      else
        if (millis()<(ledlastflashtime+2*t1+125+t2))
          set_led_rgb(led,0,0,0);
        else
          ledlastflashtime=millis();
}

// white strobe, can be combined with rgb patterns 
// (t1=strobe interval, t2=rgb interval)  50-200ms is a good value for t1
// call for each LED
void strobe (uint8_t led,int t1,int t2) {
  if (millis()<(ledlastflashtime+t2))
    ;
  else 
    if (millis()<(ledlastflashtime+t1+t2))
      set_led_rgb(led,255,255,255);
    else
      ledlastflashtime=millis();
}  

// combo rgb with white strobe (all in one function)
// t1=strobe interval, t2=rgb interval)   50-200ms is a good value for t1
// call for each LED
void rgbStrobe (uint8_t led,uint8_t red,uint8_t green,uint8_t blue,int t1,int t2) {
  if (millis()<(ledlastflashtime+t2))
    set_led_rgb(led,red,green,blue);
  else 
    if (millis()<(ledlastflashtime+t1+t2))
      set_led_rgb(led,255,255,255);
    else
      ledlastflashtime=millis();
}  

// alternating even/odd LED flasher - single color channel 
// rgb1 and t1=odd LEDs, rgb2 and t2=even LEDs)
// call once for entire ring
void altFlasher (uint8_t rgb1,uint8_t rgb2,int t1,int t2) {
  if (millis()<(ledlastflashtime+t1)) {
    for (uint8_t led=0;led<11;led=led+2) {
      set_led_unicolor(led,rgb1,255);
      set_led_rgb(led+1,0,0,0);
    } 
  } else {
    if (millis()<(ledlastflashtime+250)) {
      for (uint8_t led=1;led<12;led=led+2) {
        set_led_unicolor(led,rgb2,255);
        set_led_rgb(led-1,0,0,0);
      }
    } else
      ledlastflashtime=millis();
  }
}

// Rotate the current LED sequence in steps
// dir 1=ccw, 2=cw  t controls step time. Increase t for slower speed.
void rotate (uint8_t dir,int t) {
  for (int i=0;i<12;i++) {
    wait(t);
    memcpy(copybright,brightness,36);
    if (dir==1) {
      for (led=0;led<12;led++)   
        for (rgb=0;rgb<3;rgb++)
          brightness[rgb][led]=copybright[rgb][LEDPos(led-1)];
    }
    else
      if (dir==2) {
        for (led=11;led>=0&&led!=255;led--)   
          for (rgb=0;rgb<3;rgb++)
            brightness[rgb][led]=copybright[rgb][LEDPos(led+1)];
      }
  }
}

// advance the rgb setting of LED #1 around the ring in steps
// dir 1=ccw, 2=cw  t controls step time. Increase t for slower speed.
void advance (uint8_t dir,int t) {
  wait(t);
  if (dir==1)
    for (led=1;led<12;led++) {   
      for (rgb=0;rgb<3;rgb++)
        brightness[rgb][led]=brightness[rgb][LEDPos(led-1)];
      wait(t);
    }
  if (dir==2)
    for (led=11;led>=0&&led!=255;led--) {   
      for (rgb=0;rgb<3;rgb++)
        brightness[rgb][led]=brightness[rgb][LEDPos(led+1)];
      wait(t);      
    }
}
// alternating advance of two rgb colors around the ring (clockwise)
void altAdvance (uint8_t red1,uint8_t green1,uint8_t blue1,uint8_t red2,uint8_t green2,uint8_t blue2,int t) {
  for (led=11;led>=0&&led!=255;led--) {
    set_led_rgb(led,red1,green1,blue1);
    wait(t);
  }
  for (led=11;led>=0&&led!=255;led--) {
    set_led_rgb(led,red2,green2,blue2);
    wait(t);
  }
}
  
// single channel circle chaser with tail  dir 1=ccw, 2=cw (starts at D1)
// t controls the LED step time. Increase t for slower speed.
void chaser (uint8_t rgb,uint8_t var,uint8_t dir,int t) {
  if(rgb>2)
    return;
  set_all_rgb(0,0,0);  
  if (dir==1) {
    set_led_unicolor(0,rgb,var);
    set_led_unicolor(11,rgb,var/4);
    set_led_unicolor(10,rgb,var/16);
  }
  if (dir==2) {
    set_led_unicolor(0,rgb,var);
    set_led_unicolor(1,rgb,var/4);
    set_led_unicolor(2,rgb,var/16);
  }
  rotate(dir,t);
}

// rgb LED circles on white ring  dir 1=ccw, 2=cw.
// t controls LED jump time. Increase t for slower speed.
void circle (uint8_t red,uint8_t green,uint8_t blue,uint8_t dir,int t) {
  set_all_rgb(255,255,255);
  set_led_rgb(0,red,green,blue);
  rotate(dir,t);
}

// white LED circles on RGB ring  dir 1=ccw, 2=cw.
// t controls LED jump time. Increase t for slower speed.
void circle2 (uint8_t red,uint8_t green,uint8_t blue,uint8_t dir,int t) {
  set_all_rgb(red,green,blue);
  set_led_rgb(0,255,255,255);
  rotate(dir,t);
}  

// rotating rgb tri-flash.  can be used in multiples with time delay between
// dir 1=ccw, 2=cw. Increase t for slower speed. I like t around 50ms
void rollers (uint8_t red,uint8_t green,uint8_t blue,uint8_t dir,int t) {
  if (dir==1) {
    led++;
    if (led>=12)
      led=0;
    set_all_rgb(0,0,0);
    set_led_rgb(LEDPos(led),red,green,blue);
    set_led_rgb(LEDPos(led+4),red,green,blue); 
    set_led_rgb(LEDPos(led+8),red,green,blue);
    wait(t);
  }
  if (dir==2) {
    led--;
    if (led>=12) 
      led=11;
      set_all_rgb(0,0,0);
      set_led_rgb(LEDPos(led),red,green,blue);
      set_led_rgb(LEDPos(led-4),red,green,blue); 
      set_led_rgb(LEDPos(led-8),red,green,blue);
      wait(t);
  }
}

// bounce sends an rgb LED both directions around the ring, rebounding at the far end and returning
// start position LED (range=0 to 11) and step time are specified.
void bounce (uint8_t red,uint8_t green,uint8_t blue,uint8_t start, int t) {
  memcpy(copybright,brightness,36);
  for (led=start;led<(start+7);led++) {
    set_led_rgb(LEDPos(led),red,green,blue);
    set_led_rgb(LEDPos(2*start-led),red,green,blue);
    wait(t);
    memcpy(brightness,copybright,36);
  }
  for (led=(start+6);led>=start&&led!=255;led--) {
    set_led_rgb(LEDPos(led),red,green,blue);
    set_led_rgb(LEDPos(2*start-led),red,green,blue);
    wait(t);
    memcpy(brightness,copybright,36);
  }
}
// permutation of bounce that sweeps the disk with rgb color, then sweeps it back to what was there before
void sweep (uint8_t red,uint8_t green,uint8_t blue,uint8_t start,int t) {
  memcpy(copybright,brightness,36);
  for (led=start;led<(start+7);led++) {
    set_led_rgb(LEDPos(led),red,green,blue);
    set_led_rgb(LEDPos(2*start-led),red,green,blue);
    wait(t);
  }
  for (led=(start+6);led>=start&&led!=255;led--) {
    set_led_rgb(LEDPos(led),copybright[0][LEDPos(led)],copybright[1][LEDPos(led)],copybright[2][LEDPos(led)]);
    set_led_rgb(LEDPos(2*start-led),copybright[0][LEDPos(led)],copybright[1][LEDPos(led)],copybright[2][LEDPos(led)]);
    wait(t);
  }
}
// creates a color gradient between two rgb colors across the ring
// start is the LED position of rgb1 (range = 0 to 11).  rgb2 will be at start+6, with a gradient between.
void gradient (uint8_t red1,uint8_t green1,uint8_t blue1,uint8_t red2,uint8_t green2,uint8_t blue2,uint8_t start) {
  red=red1; green=green1; blue=blue1;
  set_led_rgb(start,red,green,blue);
  set_led_rgb(start+6,red2,green2,blue2);
  for (led=(start+1);led<(start+6);led++) {
    red=red+(red2-red1)/6;
    green=green+(green2-green1)/6;
    blue=blue+(blue2-blue1)/6;
    set_led_rgb(LEDPos(led),red,green,blue);
    set_led_rgb(LEDPos(led+6),red,green,blue);
  }
}
// color morph between two rgb colors.  Specify colors and step time interval.
void morph(int red1,int green1,int blue1,int red2,int green2,int blue2,int t) {
  red=red1;green=green1;blue=blue1;
  for (int val=0;val<101;val++) {
    red=(red1+(red2-red1)/100*val);
    green=(green1+(green2-green1)/100*val);
    blue=(blue1+(blue2-blue1)/100*val);
    set_all_rgb(red,green,blue);
    wait(t);  
  }   
}
// rgb cyclic fader for all LEDs, 100 steps from dark to full on.
// t is time between steps. t=10ms gives ~2sec cycle
void breather (int16_t red,int16_t green,int16_t blue,int t) { 
  for (int val=0;val<101;val++) {
    set_all_rgb(uint8_t(val*red/100),uint8_t(val*green/100),uint8_t(val*blue/100));
    wait(t);
  }
  for (int val=100;(val>=0 && val!=255);val--) {
    set_all_rgb(uint8_t(val*red/100),uint8_t(val*green/100),uint8_t(val*blue/100));
    wait(t);
  }
}
// rgb pointer centered on one LED (for compass display)
void pointer (uint8_t rgb,uint8_t start) {
  set_led_rgb(start,255,255,255);
  set_led_unicolor(LEDPos(start+1),rgb,255);
  set_led_unicolor(LEDPos(start-1),rgb,255);   
  set_led_unicolor(LEDPos(start+2),rgb,50);
  set_led_unicolor(LEDPos(start-2),rgb,50);   
}
// strobing navi lights - combines one of the static navi layouts with strobing
// t1 is strobe time, t2 is on time.  t1=100 and t2=350 replicates the Shikra running lights
void navStrobe (uint8_t layout,int t1,int t2) {
  if (millis()<(ledlastflashtime+t1))
    set_all_rgb(255,255,255);
  else
    if (millis()<(ledlastflashtime+t2))
      LED_layout(layout);
    else 
      if (millis()<(ledlastflashtime+t1+t2))
        set_all_rgb(255,255,255);
      else 
        if (millis()<(ledlastflashtime+2*t2))
          LED_layout(layout);
        else 
          if (millis()<(ledlastflashtime+2*t2+t1))
            set_all_rgb(255,0,0);
          else 
            if (millis()<(ledlastflashtime+5*t2-t1))
              LED_layout(layout);
            else
              ledlastflashtime=millis();
}
// LED position calculator
// This function is called to interpret octal values outside the 0-11 LED position range
// in calculations made during rotation and translation LED functions.
uint8_t LEDPos (uint8_t led) {
  if (led<12&&led>=0&&led!=255)
    pos=led;
  else
    if (led>11&&led<241)   
      pos=led%12;
      else
        pos=12-(256-led);
  return(pos);
}

